package com.example.minademo;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.example.androidmifarecarddemo.R;
import com.example.minademo.interfaces.IMsgCallback;
import com.example.minademo.server.ServerHandler;

public class MainActivity extends Activity implements IMsgCallback{

	public final String TAG = "MainActivity";

	private final static Logger LOGGER = LoggerFactory
			.getLogger(MainActivity.class);

	// private final String ADDRESS = "106.120.238.134";
	// private final int PORT = 25200;
	private final String ADDRESS = "127.0.0.1";
	private final int PORT = 8080;

	private final int CONNECT_SERVER_SUCCESS = 1;
	private final int CONNECT_SERVER_FAIL = 2;
	private final int CREATE_SERVER_SUCCESS = 3;
	private final int CREATE_SERVER_FAIL = 4;
	private final int CONNECT_HTTP_SERVER_SUCCESS = 5;
	private final int REFRESH_TV_CONTENT = 6;

	private final String CHAR_SET = ChangeCharSet.US_ASCII;
	private final int THEAD_POOL_NUM = 5;

	private ExecutorService service = null;
	private Context ctx;
	private EditText etInput;
	private TextView tvClientRcv;
	private TextView tvServerRcv;

	/** The client session */
	private IoSession clientSession;
	/** The server acceptor */
	private IoAcceptor acceptor;

	private StringBuffer clientReceiveMsg = new StringBuffer(
			"Client Receive Msg: \n");
	private StringBuffer serverRcvMsg = new StringBuffer(
			"Server Receive Msg: \n");

	private Handler myHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {

			switch (msg.what) {

			case CONNECT_SERVER_SUCCESS:
				Toast.makeText(ctx, "connect to server success",
						Toast.LENGTH_SHORT).show();
				break;

			case CREATE_SERVER_SUCCESS:
				Toast.makeText(ctx, "create server success", Toast.LENGTH_SHORT)
						.show();

				connectServer();
				break;

			case CONNECT_SERVER_FAIL:
				Toast.makeText(ctx, "connect to server fail",
						Toast.LENGTH_SHORT).show();
				break;
			case CREATE_SERVER_FAIL:
				Toast.makeText(ctx, "create server fail", Toast.LENGTH_SHORT)
						.show();
				break;

			case CONNECT_HTTP_SERVER_SUCCESS:

				Bundle data = msg.getData();
				String rsp = data.getString("msg");

				Toast.makeText(ctx, "http rsp: " + rsp, Toast.LENGTH_SHORT)
						.show();
				break;

			case REFRESH_TV_CONTENT:

				if (null != tvClientRcv) {

					tvClientRcv.setText(clientReceiveMsg.toString());
				}

				if (null != tvServerRcv) {

					tvServerRcv.setText(serverRcvMsg.toString());
				}

				break;
			}
		}

	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_mina);

		ctx = this;

		etInput = (EditText) findViewById(R.id.input_msg);

		tvClientRcv = (TextView) findViewById(R.id.client_receive_msg);

		tvServerRcv = (TextView) findViewById(R.id.server_receive_msg);

		service = Executors.newFixedThreadPool(THEAD_POOL_NUM);

		// 启动server程序
		startServer();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	protected void onDestroy() {

		super.onDestroy();
		closeConnect();
		closeServer();
	}

	public void connectServer() {

		if (service == null) {

			return;
		}

		service.submit(new Runnable() {

			@Override
			public void run() {

				connectToServer();
			}
		});
	}

	public void startServer() {

		Log.d(TAG, "onCreateServerClicked");

		if (service == null) {

			return;
		}

		service.submit(new Runnable() {

			@Override
			public void run() {

				createServer();
			}
		});

	}

	private void createServer() {

		acceptor = new NioSocketAcceptor();

		try {

			DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();

			TextLineCodecFactory factory = new TextLineCodecFactory(
					Charset.forName(CHAR_SET));

			factory.setDecoderMaxLineLength(Integer.MAX_VALUE);
			factory.setEncoderMaxLineLength(Integer.MAX_VALUE);

			chain.addLast("codec", new ProtocolCodecFilter(factory));

			acceptor.setHandler(new ServerHandler(this));
			acceptor.bind(new InetSocketAddress(ADDRESS, PORT));

			myHandler.sendEmptyMessage(CREATE_SERVER_SUCCESS);
		} catch (IOException e) {
			System.out.println("cat io exception");

			Log.d("Main", "cat exp: " + e.getMessage());
			e.printStackTrace();
		}

	}

	private void closeServer() {

		if (null != acceptor && !acceptor.isDisposing()) {

			acceptor.dispose();
		}
	}

	private void closeConnect() {

		if (null != clientSession && !clientSession.isClosing()) {

			clientSession.close(false);
		}
	}

	private void connectToServer() {

		NioSocketConnector connector = new NioSocketConnector();

		DefaultIoFilterChainBuilder chain = connector.getFilterChain();

		TextLineCodecFactory factory = new TextLineCodecFactory(
				Charset.forName(CHAR_SET));

		factory.setDecoderMaxLineLength(Integer.MAX_VALUE);
		factory.setEncoderMaxLineLength(Integer.MAX_VALUE);

		chain.addLast("codec", new ProtocolCodecFilter(factory));

		connector.setHandler(new ClientMinaHandler(this));
		connector.setConnectTimeoutCheckInterval(30);

		Log.d(TAG, "begin connect server");

		ConnectFuture cf = connector.connect(new InetSocketAddress(ADDRESS,
				PORT));

		cf.awaitUninterruptibly();

		clientSession = cf.getSession();
		// connector.dispose();
		Log.d(TAG, "connect success ~");
		myHandler.sendEmptyMessage(CONNECT_SERVER_SUCCESS);
	}

	public void onSendMsgClicked(View v) {

		Log.d(TAG, "send msg button clicked");

		if (null != etInput) {

			String inputMsg = etInput.getText().toString();

			Log.d(TAG, "begin write msg to server,msg: " + inputMsg);

			if (null != inputMsg && null != clientSession) {

				Log.d(TAG, "write msg now...");

				clientSession.write(inputMsg);
			}
		}
	}

	@Override
	public void clientReceiveMsg(String msg) {

		clientReceiveMsg.append(msg + "\n");

		myHandler.sendEmptyMessage(REFRESH_TV_CONTENT);
	}

	@Override
	public void serverReceiveMsg(String msg) {

		serverRcvMsg.append(msg + "\n");

		myHandler.sendEmptyMessage(REFRESH_TV_CONTENT);
	}
}
